namespace Stee.CAP8.Health
{
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using NLog;

    public static class ServiceContext
    {
        private static readonly IDictionary<Type, bool> ServiceReadyness = new Dictionary<Type, bool>();
        private static readonly IDictionary<Type, bool> ServiceDegraded = new Dictionary<Type, bool>();
        private static readonly Logger Logger = LogManager.GetCurrentClassLogger();

        #region Health check

        /// <summary>
        /// All gRPC service need to register before initialization.
        /// By default: a new registered service is not ready to accept request. 
        ///   And it is not in degraded mode.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        public static void RegisterService<T>()
        {
            var serviceType = typeof(T);
            if (Logger.IsDebugEnabled)
            {
                Logger.Debug($"{nameof(RegisterService)} start. Service Type: {serviceType.FullName}");
            }
            if (ServiceReadyness.ContainsKey(serviceType))
            {
                Logger.Error($"Service Type '{serviceType.FullName}' is already registered.");
                return;
            }
            ServiceReadyness.Add(serviceType, false);
            ServiceDegraded.Add(serviceType, false);
        }
        /// <summary>
        /// Set service readiness.
        /// gRPC service required to call this function after initialized 
        /// and ready to accept request.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="ready">
        ///  true: ready. false: not ready
        /// </param>
        public static void SetServiceReadiness<T>(bool ready)
        {
            var serviceType = typeof(T);
            if (Logger.IsDebugEnabled)
            {
                Logger.Debug($"{nameof(SetServiceReadiness)} start. Service Type: {serviceType.FullName}, ready: {ready}");
            }
            if (ServiceReadyness.ContainsKey(serviceType))
            {
                ServiceReadyness[serviceType] = ready;
            }
            else
            {
                Logger.Error($"Service Type '{serviceType.FullName}' is not registered.");
                
            }
        }
        /// <summary>
        /// Set service in degraded mode.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="degraded"></param>
        public static void SetServiceInDegradeModel<T>(bool degraded)
        {
            var serviceType = typeof(T);
            if (Logger.IsDebugEnabled)
            {
                Logger.Debug($"{nameof(SetServiceInDegradeModel)} start. Service Type: {serviceType.FullName}, DegradedMode: {degraded}");
            }
            if (ServiceDegraded.ContainsKey(serviceType))
            {
                ServiceDegraded[serviceType] = degraded;
            }
            else
            {
                Logger.Error($"Service Type '{serviceType.FullName}' is not registered.");
            }
        }


        internal static bool IsReady()
        {
            if (ServiceReadyness.Any())
            {
                if (ServiceReadyness.Any(t => !t.Value))
                {
                    if (Logger.IsInfoEnabled)
                    {
                        var notReadyServices = string.Join(',', ServiceReadyness.Where(t => !t.Value)
                            .Select(t => t.Key.FullName));
                        Logger.Info($"This services are not ready: {notReadyServices}");
                    }
                    return false;
                }
                return true;
            }
            else // no registered service
            {
                return false;
            }
        }

        internal static bool IsDegraded()
        {
            if (ServiceDegraded.Any(t => t.Value))
            {
                if (Logger.IsInfoEnabled)
                {
                    var degradedServices = string.Join(',', ServiceDegraded.Where(t => t.Value)
                        .Select(t => t.Key.FullName));
                    Logger.Info($"This services are in degraded mode: {degradedServices}");
                }

                return true;
            }
            else // no registered service
            {
                return false;
            }
        }
        #endregion Health check


    }



}
